package com.chinatelecom.common.thread;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

/**
 * 消息处理中心，建议使用此handle来处理消息
 *
 * @author zhangluya on 2015/11/2.
 * @version 1.0 2015-11-02
 */
public class MessageCenterHandler extends Handler {

    // 为防止内存泄漏，弱引用目标对象，让系统能更好的回收内存
    private Map<String, Object> mObjects = new WeakHashMap<>();

    /**
     * UI线程的handler
     */
    private static MessageCenterHandler mMainHandler;
    private static Object mMainHandlerLock = new Object();

    /**
     * 子线程handler
     */
    private static Handler mFileThreadHandler;
    private static HandlerThread mFileThread;


    private MessageCenterHandler(Looper looper) {
        super(looper);
    }

    /**
     * 取得UI线程Handler
     *
     * @return
     */
    public static MessageCenterHandler getMainHandler() {
        if(mMainHandler == null) {
            synchronized (mMainHandlerLock) {
                if(mMainHandler == null) {
                    mMainHandler = new MessageCenterHandler(Looper.getMainLooper());
                }
            }
        }
        return mMainHandler;
    }

    /**
     * 获得文件线程的Handler.
     * 此线程可以执行本地文件读写等比较快但不能在ui线程执行的操作.
     * 此线程禁止进行网络操作.
     *
     * @return handler
     */
    public static Handler getSubThreadHandler() {
        if (mFileThreadHandler == null) {
            synchronized (MessageCenterHandler.class) {
                mFileThread = new HandlerThread("FILE_THREAD");
                mFileThread.start();
                mFileThreadHandler = new Handler(mFileThread.getLooper());
            }
        }
        return mFileThreadHandler;
    }


    public static void executeOnFileThread(Runnable r) {
        getSubThreadHandler().post(r);
    }

    public void prepareHandleMessage(Object target) {
        if(target == null) {
            throw new NullPointerException("The object reference cannot be empty .");
        }
        mObjects.put(target.getClass().getName(), target);
    }

    public void removeTarget(Object target) {
        if(target != null && mObjects.containsKey(target.getClass().getName())) {
            mObjects.remove(target.getClass().getName());
        }
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        invokeTarget(msg);
    }

    /**
     * 调用目标接口的指定方法
     *
     * @return
     *         交互结果
     */
    private Object invokeTarget(Message msg) {
        final Set<Map.Entry<String, Object>> entries = mObjects.entrySet();
        final Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            final Map.Entry<String, Object> entry = iterator.next();
            final Object target = mObjects.get(entry.getKey());
            if (target != null) {
                final Class<?> clazz = target.getClass();
                final Method[] methods = clazz.getMethods();
                for (Method m : methods) {
                    final boolean isAnnotationPresent = m.isAnnotationPresent(MessageHandler.class);
                    if (isAnnotationPresent) {
                        final MessageHandler messageHandler = m.getAnnotation(MessageHandler.class);
                        final int what = messageHandler.value();
                        if (what == msg.what) {
                            try {
                                final Object retValue = m.invoke(target, msg);
                                return retValue;
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
        return null;
    }
}
